
#include "ByteDeSerializer.h"
#include "ByteSerializer.h"
#include "HashFunctions.h"
#include "Common/Errors.h"

using namespace ttg;
using namespace ttg::extras::serialization;
using namespace ttg_internal::extras::serialization;

//------------------------
//--- ByteDeSerializer ---
//------------------------

unsigned __int32 ByteDeSerializer::readHash()
{
	unsigned __int32 res;
	for (size_t i = 0; i < 4; i++)
		((unsigned char *)&res)[i] = data[current++];
	return res;
}

void ByteDeSerializer::checkData(size_t size)
{
	if (data_size - current < size)
		throw ttg::Error(Error::LOCAL, "ByteDeSerializer", "checkData",
						 "End of byte stream has been reached");
}

void ByteDeSerializer::deserializeMemory(void *data, size_t size, const char *name)
{
	//Checking.
	if (is_safe)
	{
		checkData(size + 4);
		if (readHash() != hashFunc(name, size) << 2)
			throw ttg::Error(Error::LOCAL, "ByteDeSerializer", "deserializeMemory",
							 "Wrong hash value");
	}
	else
		checkData(size);
	//Reading.
	for (size_t i = 0; i < size; i++)
	{
		((unsigned char *)data)[i] = this->data[current++];
	}
}

void ByteDeSerializer::deserializeReferenceStart(bool &is_null, const char *name)
{
	if (is_safe)
	{
		//Checking.
		checkData(4);
		unsigned __int32 hash = readHash();
		if ((hash & ~3) != (hashFunc(name, 0) << 2))
			throw ttg::Error(Error::LOCAL, "ByteDeSerializer", "deserializeReferenceStart",
							 "Wrong hash");
		//Reading.
		unsigned __int32 flag = hash & 3;
		if (flag == 1)
			is_null = false; else
		if (flag == 2)
			is_null = true;
		else
			throw ttg::Error(Error::LOCAL, "ByteDeSerialization", "deserializeReferenceStart",
							 "Unknow type of serialized data");
	}
	else
	{
		//Checking.
		checkData(1);
		//Reading.
		unsigned char flag = data[current++];
		if (flag == NullReferenceFlag)
			is_null = true; else
		if (flag == NotNullReferenceFlag)
			is_null = false;
		else
			throw ttg::Error(Error::FATAL, "ByteDeSerialization", "deserializeReferenceStart",
							 "Wrong reference type");
	}
}

void ByteDeSerializer::deserializeReferenceEnd(const char *name)
{
	if (is_safe &&
		data[current++] != ReferenceEnd)
	{
		throw ttg::Error(Error::FATAL, "ByteDeSerializer", "deserializeReferenceEnd",
						 "Reference end is not found");
	}
}

ByteDeSerializer::ByteDeSerializer(void *data, size_t size)
{
	//Setting fields.
	this->data = (unsigned char *)data;
	this->data_size = size;
	this->current = 0;
	//Detecting serialization type.
	unsigned char serialization_type = this->data[current++];
	if (serialization_type == SafeSerialization)
		is_safe = true; else
	if (serialization_type == NotSafeSerialization)
		is_safe = false;
	else
		throw ttg::Error(Error::FATAL, "ByteDeSerializer", "ByteDeSerializer",
						 "Unknown type of byte stream");
}
